home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
SGI Developer Toolbox 6.1
/
SGI Developer Toolbox 6.1 - Disc 1.iso
/
toolbox
/
src
/
exampleCode
/
opengl
/
extensions
/
samples
/
surfgrid.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-11-11
|
22KB
|
697 lines
/*
* Copyright (c) 1994 Silicon Graphics, Inc.
*
* Permission to use, copy, modify, distribute, and sell this software and
* its documentation for any purpose is hereby granted without fee,
* provided that (i) the above copyright notices and this permission
* notice appear in all copies of the software and related documentation,
* and (ii) the name of Silicon Graphics may not be used in any
* advertising or publicity relating to the software without the specific,
* prior written permission of Silicon Graphics.
*
* THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
* EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
* WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
*
* IN NO EVENT SHALL SILICON GRAPHICS BE LIABLE FOR ANY SPECIAL,
* INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
* OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
* LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
/*
* surfgrid.c - demonstration of polygon_offset extension
*
* 1994 Simon Hui - Silicon Graphics Computer Systems
*
* $Revision: 1.1 $
*
* usage:
* surfgrid [-f (full screen)] [-h(elp)]
*
* The program displays a torus made of bezier patches. The outline of the
* patches is displayed as lines drawn on the surface. polygon_offset is used to
* displace the depth of the patches so it does not interfere with the lines.
*
* keys:
* p toggle polygon offset
* m toggle multisampling
* s toggle surface drawing
* g toggle grid drawing
* f toggle smooth/flat shading
* n toggle whether to use GL evaluators or GLU nurbs
* u decr number of segments in U direction
* U incr number of segments in U direction
* v decr number of segments in V direction
* V incr number of segments in V direction
* h help
* escape quit
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <GL/glu.h>
#include <GL/glx.h>
#include <X11/keysym.h>
#include <Xm/MwmUtil.h>
#include "util.h"
#define W 600
#define H 600
static long winwidth = W, winheight = H;
GC xgc;
Display *dpy;
Colormap cmap;
Window window;
XVisualInfo *vi;
GLXContext cx;
GLUnurbsObj *nobj;
GLuint surflist, gridlist;
int useglunurbs = 0;
int smooth = 1;
int tracking = 0;
int showgrid = 1;
int showsurf = 1;
GLboolean hasMultisampling;
float modelmatrix[16] = {
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
};
float scale = 0.5;
float bias = 0.002;
int usegments=4;
int vsegments=4;
int spindx, spindy;
int startx, starty;
int curx, cury;
void redraw(void);
void createlists(void);
Window createwindow(int argc, char **argv, Bool fullscreen);
float torusnurbpts[], torusbezierpts[];
void eventloop( void )
{
XEvent event;
XButtonEvent *bev;
int x, y, size;
unsigned int w, h, bw, depth;
Window root;
for (;;) {
if (XPending(dpy)) {
XNextEvent(dpy, &event);
bev = (XButtonEvent *) &event;
switch (event.type) {
case KeyPress:
{
char buf[100];
int rv;
KeySym ks;
rv = XLookupString(&event.xkey, buf, sizeof(buf), &ks, 0);
switch (ks) {
case XK_n:
useglunurbs = !useglunurbs;
break;
#ifdef GL_EXT_polygon_offset
case XK_p:
if (glIsEnabled( GL_POLYGON_OFFSET_EXT )) {
glDisable( GL_POLYGON_OFFSET_EXT );
printf("disabling polygon offset\n");
} else {
glEnable( GL_POLYGON_OFFSET_EXT );
printf("enabling polygon offset\n");
}
break;
#endif
#ifdef GL_SGIS_multisample
case XK_m:
if (hasMultisampling) {
if (glIsEnabled( GL_MULTISAMPLE_SGIS )) {
glDisable( GL_MULTISAMPLE_SGIS );
printf("Multisampling off\n");
} else {
glEnable( GL_MULTISAMPLE_SGIS );
printf("Multisampling on\n");
}
}
break;
#endif
case XK_g:
showgrid = !showgrid;
break;
case XK_t:
showsurf = !showsurf;
break;
case XK_f:
smooth = !smooth;
if (smooth) {
glShadeModel( GL_SMOOTH );
} else {
glShadeModel( GL_FLAT );
}
break;
case XK_S:
scale += 0.1;
printf( "scale: %g\n", scale);
break;
case XK_s:
scale -= 0.1;
printf( "scale: %g\n", scale);
break;
case XK_B:
bias += 0.0001;
printf( "bias: %g\n", bias);
break;
case XK_b:
bias -= 0.0001;
printf( "bias: %g\n", bias);
break;
case XK_u:
if (usegments > 1)
usegments--;
createlists();
break;
case XK_U:
usegments++;
createlists();
break;
case XK_v:
if (vsegments > 1)
vsegments--;
createlists();
break;
case XK_V:
vsegments++;
createlists();
break;
case XK_h:
case XK_question:
printf("Keys:\tp - toggle polygon offset\n");
printf("\tb/B - decr/incr polygon offset bias\n");
printf("\ts/S - decr/incr polygon offset scale\n");
printf("\tm - toggle multisampling\n");
printf("\tt - toggle surface drawing\n");
printf("\tg - toggle grid drawing\n");
printf("\tf - toggle smooth/flat shading\n");
printf("\tn - toggle between GL evaluators\
and GLU nurbs\n");
printf("\tu/U - decr/incr number of segments\
in U direction\n");
printf("\tv/V - decr/incr number of segments\
in V direction\n");
printf("\th/? - help\n");
printf("\tEsc - quit\n");
printf("To move the object press a mouse button\
and move the mouse\n");
break;
case XK_Escape:
exit(EXIT_SUCCESS);
break;
}
if (!XPending(dpy)) redraw();
}
break;
case Expose:
XGetGeometry(dpy, window, &root, &x, &y, &w, &h, &bw, &depth);
winwidth = w;
winheight = h;
size = (winwidth < winheight ? winwidth : winheight);
glViewport((winwidth-size)/2, (winheight-size)/2, size, size);
redraw();
break;
case ConfigureNotify:
winwidth = event.xconfigure.width;
winheight = event.xconfigure.height;
size = (winwidth < winheight ? winwidth : winheight);
glViewport((winwidth-size)/2, (winheight-size)/2, size, size);
redraw();
break;
case ButtonPress:
curx = startx = bev->x;
cury = starty = bev->y;
spindx = 0;
spindy = 0;
tracking = True;
break;
case ButtonRelease:
/*
* If user released the button while moving the mouse, keep
* spinning.
*/
if (bev->x != curx || bev->y != cury) {
spindx = bev->x - curx;
spindy = bev->y - cury;
}
tracking = False;
break;
case MotionNotify:
if (XPending(dpy))
break;
curx = bev->x;
cury = bev->y;
if (curx != startx || cury != starty) {
redraw();
startx = curx;
starty = cury;
}
break;
}
} else {
if (!tracking && (spindx!=0 || spindy!=0)) {
redraw();
}
}
}
}
void gridmaterials(void)
{
float front_mat_diffuse[] = { 0, 0, 0, 0 };
float front_mat_ambient[] = { 0, 0, 0, 0 };
float back_mat_diffuse[] = { 0, 0, 0, 0 };
float back_mat_ambient[] = { 0, 0, 0, 0 };
glMaterialfv(GL_FRONT, GL_DIFFUSE, front_mat_diffuse);
glMaterialfv(GL_FRONT, GL_AMBIENT, front_mat_ambient);
glMaterialfv(GL_BACK, GL_DIFFUSE, back_mat_diffuse);
glMaterialfv(GL_BACK, GL_AMBIENT, back_mat_ambient);
}
void surfacematerials(void)
{
float front_mat_diffuse[] = { 0.2, 0.7, 0.4, 1.0 };
float front_mat_ambient[] = { 0.1, 0.1, 0.1, 1.0 };
float back_mat_diffuse[] = { 1.0, 1.0, 0.2, 1.0 };
float back_mat_ambient[] = { 0.1, 0.1, 0.1, 1.0 };
glMaterialfv(GL_FRONT, GL_DIFFUSE, front_mat_diffuse);
glMaterialfv(GL_FRONT, GL_AMBIENT, front_mat_ambient);
glMaterialfv(GL_BACK, GL_DIFFUSE, back_mat_diffuse);
glMaterialfv(GL_BACK, GL_AMBIENT, back_mat_ambient);
}
void init(int argc, char **argv, int fullscreen)
{
int i;
float ambient[] = { 0.0, 0.0, 0.0, 1.0 };
float diffuse[] = { 1.0, 1.0, 1.0, 1.0 };
float position[] = { 90.0, 90.0, -150.0, 0.0 };
float lmodel_ambient[] = { 1.0, 1.0, 1.0, 1.0 };
float lmodel_twoside[] = { GL_TRUE };
window = createwindow( argc, argv, fullscreen );
cx = glXCreateContext(dpy, vi, 0, GL_TRUE);
if (!glXMakeCurrent(dpy, window, cx)) {
fprintf(stderr, "Can't make window current to context\n");
exit(EXIT_FAILURE);
}
if (!getExtension("GL_EXT_polygon_offset")) {
fprintf(stderr, "Sorry GL_EXT_polygon_offset is not supported.\n");
exit(EXIT_FAILURE);
}
glLineWidth(2);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective( 40.0, 1.0, 2.0, 200.0 );
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
glLightfv(GL_LIGHT0, GL_POSITION, position);
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_DEPTH_TEST);
glEnable(GL_AUTO_NORMAL);
glFrontFace(GL_CCW);
glEnable( GL_MAP2_VERTEX_4 );
glClearColor(0.25, 0.25, 0.5, 0.0);
#ifdef GL_EXT_polygon_offset
glEnable(GL_POLYGON_OFFSET_EXT);
glPolygonOffsetEXT( scale, bias );
#endif
nobj = gluNewNurbsRenderer();
gluNurbsProperty(nobj, GLU_SAMPLING_METHOD, GLU_DOMAIN_DISTANCE );
surflist = glGenLists(1);
gridlist = glGenLists(1);
createlists();
}
void drawmesh(void)
{
int i, j;
float *p;
int up2p = 4;
int uorder = 3, vorder = 3;
int nu = 4, nv = 4;
int vp2p = up2p * uorder * nu;
for (j=0; j < nv; j++) {
for (i=0; i < nu; i++) {
p = torusbezierpts + (j * vp2p * vorder) + (i * up2p * uorder);
#ifdef GL_EXT_polygon_offset
glPolygonOffsetEXT( scale, bias );
#endif
glMap2f( GL_MAP2_VERTEX_4, 0.0, 1.0, up2p, 3, 0.0, 1.0, vp2p, 3,
(void*)p );
if (showsurf) {
surfacematerials();
glEvalMesh2( GL_FILL, 0, usegments, 0, vsegments );
}
if (showgrid) {
gridmaterials();
glEvalMesh2( GL_LINE, 0, usegments, 0, vsegments );
}
}
}
}
void redraw(void)
{
static int i=0;
int dx, dy;
float v[3], n[3], rot[3];
float len, rlen, ang;
static GLuint vcount;
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glColor3f( 1, 0, 0);
if (tracking) {
dx = curx - startx;
dy = cury - starty;
} else {
dx = spindx;
dy = spindy;
}
if (dx || dy) {
dy = -dy;
v[0] = dx;
v[1] = dy;
v[2] = 0;
len = length(v);
ang = -len / 600 * 360;
norm( v );
cross( v, z_axis, rot );
/*
** We concatenate the rotation onto the current modelview matrix and
** read the matrix back, thus saving ourselves from writing our own
** matrix manipulation routines.
** This is certainly not recommended for programs that care
** about performance or numerical stability :-)
*/
glLoadIdentity();
glRotatef(ang, rot[0], rot[1], rot[2]);
glMultMatrixf(modelmatrix);
glGetFloatv(GL_MODELVIEW_MATRIX, modelmatrix);
}
glLoadIdentity();
glTranslatef( 0.0, 0.0, -10.0 );
glMultMatrixf(modelmatrix);
if (useglunurbs) {
if (showsurf) glCallList(surflist);
if (showgrid) glCallList(gridlist);
} else {
glMapGrid2f( usegments, 0.0, 1.0, vsegments, 0.0, 1.0 );
drawmesh();
}
glXSwapBuffers(dpy, window);
}
static void usage(char *name, int exitStatus)
{
fprintf(stderr, "usage: %s [-f (for full screen)] [-h(elp)]\n", name);
fprintf(stderr,
"\tInteractively, `h/?' keys provide description of interface\n");
exit(exitStatus);
}
void
main(int argc, char **argv)
{
int i, ms, fullscreen = 0;
for (i=1; i<argc; i++) {
if (argv[i][0] == '-') {
switch (argv[i][1]) {
case 'f':
fullscreen = 1;
break;
case 'h':
usage(argv[0], EXIT_SUCCESS);
default:
usage(argv[0], EXIT_FAILURE);
}
} else {
usage(argv[0], EXIT_FAILURE);
}
}
init(argc, argv, fullscreen);
eventloop();
glXMakeCurrent(dpy, None, NULL);
glXDestroyContext(dpy, cx);
XCloseDisplay(dpy);
}
/****************************************************************************/
float circleknots[] = { 0.0, 0.0, 0.0, 0.25, 0.50, 0.50, 0.75, 1.0, 1.0, 1.0 };
void createlists(void)
{
gluNurbsProperty(nobj, GLU_U_STEP, (usegments-1)*4 );
gluNurbsProperty(nobj, GLU_V_STEP, (vsegments-1)*4 );
gluNurbsProperty(nobj, GLU_DISPLAY_MODE, GLU_FILL);
glNewList(surflist, GL_COMPILE);
surfacematerials();
gluBeginSurface(nobj);
gluNurbsSurface(nobj, 10, circleknots, 10, circleknots,
4, 28, torusnurbpts, 3, 3, GL_MAP2_VERTEX_4);
gluEndSurface(nobj);
glEndList();
gluNurbsProperty(nobj, GLU_DISPLAY_MODE, GLU_OUTLINE_POLYGON);
glNewList(gridlist, GL_COMPILE);
gridmaterials();
gluBeginSurface(nobj);
gluNurbsSurface(nobj, 10, circleknots, 10, circleknots,
4, 28, torusnurbpts, 3, 3, GL_MAP2_VERTEX_4);
gluEndSurface(nobj);
glEndList();
}
/****************************************************************************/
/*
* Create an X window.
*/
static Bool WaitForMapNotify(Display *d, XEvent *e, char *arg)
{
if ((e->type == MapNotify) && (e->xmap.window == (Window)arg)) {
return GL_TRUE;
}
return GL_FALSE;
}
Window createwindow(int argc, char **argv, Bool fullscreen)
{
Window window;
XSetWindowAttributes swa;
unsigned int width, height;
XSizeHints sh;
XEvent event;
const char *extensions;
char title[100];
int attributes[] = {
#ifdef GL_SGIS_multisample
GLX_SAMPLES_SGIS,
#else
None, /* Note used - simplifies the code */
#endif
0,
GLX_RGBA,
GLX_DOUBLEBUFFER,
GLX_RED_SIZE, 1,
GLX_GREEN_SIZE, 1,
GLX_BLUE_SIZE, 1,
GLX_DEPTH_SIZE, 1,
None,
};
dpy = XOpenDisplay(0);
if (!dpy) {
fprintf(stderr, "Can't connect to display \"%s\"\n",
getenv("DISPLAY"));
exit(EXIT_FAILURE);
}
#ifdef GL_SGIS_multisample
extensions = glXQueryExtensionsString(dpy, DefaultScreen(dpy));
hasMultisampling = extensions == NULL ||
strstr(extensions, "GLX_SGIS_multisample") == NULL;
#else
hasMultisampling = GL_FALSE;
#endif
if (hasMultisampling) {
int logMs;
/* Try to get the largest number of samples */
for (vi = NULL, logMs = 4; logMs && vi == NULL; logMs--) {
attributes[1] = logMs > 1 ? 1 << logMs : 0;
vi = glXChooseVisual(dpy, DefaultScreen(dpy), attributes);
}
sprintf(title,"%s - %d samples", argv[0], attributes[1]);
} else {
vi = glXChooseVisual(dpy, DefaultScreen(dpy), &attributes[2]);
sprintf(title,"%s", argv[0]);
}
if (!vi) {
fprintf(stderr, "Cannot find visual on \"%s\"\n", getenv("DISPLAY"));
exit(EXIT_FAILURE);
}
cmap = XCreateColormap(dpy, RootWindow(dpy, vi->screen), vi->visual,
AllocNone);
swa.background_pixel = 0;
swa.border_pixel = 0;
swa.colormap = cmap;
swa.event_mask = ExposureMask | StructureNotifyMask | KeyPressMask |
KeyReleaseMask | ButtonPressMask | ButtonMotionMask | ButtonReleaseMask;
if (fullscreen) {
width = DisplayWidth( dpy, 0 );
height = DisplayHeight( dpy, 0 );
sh.x = 0;
sh.y = 0;
} else {
width = winwidth;
height = winheight;
sh.x = 50;
sh.y = 50;
}
sh.flags = USPosition | PPosition;
window = XCreateWindow(dpy, RootWindow(dpy, vi->screen), sh.x, sh.y,
width, height,
0, vi->depth, InputOutput, vi->visual,
CWBorderPixel|CWColormap|CWEventMask|CWBackPixel,
&swa);
XSetStandardProperties(dpy, window, title, argv[0], None, argv, argc, &sh);
XSetWMColormapWindows(dpy, window, &window, 1);
if (fullscreen) {
/* turn off window decorations */
Atom hints_atom;
MotifWmHints hints;
hints_atom = XInternAtom( dpy, "_MOTIF_WM_HINTS", 0 );
hints.flags = MWM_HINTS_DECORATIONS;
hints.decorations = 0;
XChangeProperty( dpy, window, hints_atom, hints_atom, 32,
PropModeReplace, (unsigned char*)&hints, 5 );
}
XMapWindow(dpy, window);
XIfEvent(dpy, &event, WaitForMapNotify, (char*)window);
return window;
}
/*
* Control points of the torus in Bezier form. Can be rendered
* using OpenGL evaluators.
*/
static GLfloat torusbezierpts[] = {
4.0, 0.0, 0.0, 4.0, 2.0, 0.0, 1.0, 2.0, 3.0, 0.0, 1.0, 2.0,
3.0, 0.0, 1.0, 2.0, 4.0, 0.0, 1.0, 2.0, 8.0, 0.0, 0.0, 4.0,
8.0, 0.0, 0.0, 4.0, 4.0, 0.0,-1.0, 2.0, 3.0, 0.0,-1.0, 2.0,
3.0, 0.0,-1.0, 2.0, 2.0, 0.0,-1.0, 2.0, 4.0, 0.0, 0.0, 4.0,
2.0,-2.0, 0.0, 2.0, 1.0,-1.0, 0.5, 1.0, 1.5,-1.5, 0.5, 1.0,
1.5,-1.5, 0.5, 1.0, 2.0,-2.0, 0.5, 1.0, 4.0,-4.0, 0.0, 2.0,
4.0,-4.0, 0.0, 2.0, 2.0,-2.0,-0.5, 1.0, 1.5,-1.5,-0.5, 1.0,
1.5,-1.5,-0.5, 1.0, 1.0,-1.0,-0.5, 1.0, 2.0,-2.0, 0.0, 2.0,
0.0,-2.0, 0.0, 2.0, 0.0,-1.0, 0.5, 1.0, 0.0,-1.5, 0.5, 1.0,
0.0,-1.5, 0.5, 1.0, 0.0,-2.0, 0.5, 1.0, 0.0,-4.0, 0.0, 2.0,
0.0,-4.0, 0.0, 2.0, 0.0,-2.0,-0.5, 1.0, 0.0,-1.5,-0.5, 1.0,
0.0,-1.5,-0.5, 1.0, 0.0,-1.0,-0.5, 1.0, 0.0,-2.0, 0.0, 2.0,
0.0,-2.0, 0.0, 2.0, 0.0,-1.0, 0.5, 1.0, 0.0,-1.5, 0.5, 1.0,
0.0,-1.5, 0.5, 1.0, 0.0,-2.0, 0.5, 1.0, 0.0,-4.0, 0.0, 2.0,
0.0,-4.0, 0.0, 2.0, 0.0,-2.0,-0.5, 1.0, 0.0,-1.5,-0.5, 1.0,
0.0,-1.5,-0.5, 1.0, 0.0,-1.0,-0.5, 1.0, 0.0,-2.0, 0.0, 2.0,
-2.0,-2.0, 0.0, 2.0,-1.0,-1.0, 0.5, 1.0,-1.5,-1.5, 0.5, 1.0,
-1.5,-1.5, 0.5, 1.0,-2.0,-2.0, 0.5, 1.0,-4.0,-4.0, 0.0, 2.0,
-4.0,-4.0, 0.0, 2.0,-2.0,-2.0,-0.5, 1.0,-1.5,-1.5,-0.5, 1.0,
-1.5,-1.5,-0.5, 1.0,-1.0,-1.0,-0.5, 1.0,-2.0,-2.0, 0.0, 2.0,
-4.0, 0.0, 0.0, 4.0,-2.0, 0.0, 1.0, 2.0,-3.0, 0.0, 1.0, 2.0,
-3.0, 0.0, 1.0, 2.0,-4.0, 0.0, 1.0, 2.0,-8.0, 0.0, 0.0, 4.0,
-8.0, 0.0, 0.0, 4.0,-4.0, 0.0,-1.0, 2.0,-3.0, 0.0,-1.0, 2.0,
-3.0, 0.0,-1.0, 2.0,-2.0, 0.0,-1.0, 2.0,-4.0, 0.0, 0.0, 4.0,
-4.0, 0.0, 0.0, 4.0,-2.0, 0.0, 1.0, 2.0,-3.0, 0.0, 1.0, 2.0,
-3.0, 0.0, 1.0, 2.0,-4.0, 0.0, 1.0, 2.0,-8.0, 0.0, 0.0, 4.0,
-8.0, 0.0, 0.0, 4.0,-4.0, 0.0,-1.0, 2.0,-3.0, 0.0,-1.0, 2.0,
-3.0, 0.0,-1.0, 2.0,-2.0, 0.0,-1.0, 2.0,-4.0, 0.0, 0.0, 4.0,
-2.0, 2.0, 0.0, 2.0,-1.0, 1.0, 0.5, 1.0,-1.5, 1.5, 0.5, 1.0,
-1.5, 1.5, 0.5, 1.0,-2.0, 2.0, 0.5, 1.0,-4.0, 4.0, 0.0, 2.0,
-4.0, 4.0, 0.0, 2.0,-2.0, 2.0,-0.5, 1.0,-1.5, 1.5,-0.5, 1.0,
-1.5, 1.5,-0.5, 1.0,-1.0, 1.0,-0.5, 1.0,-2.0, 2.0, 0.0, 2.0,
0.0, 2.0, 0.0, 2.0, 0.0, 1.0, 0.5, 1.0, 0.0, 1.5, 0.5, 1.0,
0.0, 1.5, 0.5, 1.0, 0.0, 2.0, 0.5, 1.0, 0.0, 4.0, 0.0, 2.0,
0.0, 4.0, 0.0, 2.0, 0.0, 2.0,-0.5, 1.0, 0.0, 1.5,-0.5, 1.0,
0.0, 1.5,-0.5, 1.0, 0.0, 1.0,-0.5, 1.0, 0.0, 2.0, 0.0, 2.0,
0.0, 2.0, 0.0, 2.0, 0.0, 1.0, 0.5, 1.0, 0.0, 1.5, 0.5, 1.0,
0.0, 1.5, 0.5, 1.0, 0.0, 2.0, 0.5, 1.0, 0.0, 4.0, 0.0, 2.0,
0.0, 4.0, 0.0, 2.0, 0.0, 2.0,-0.5, 1.0, 0.0, 1.5,-0.5, 1.0,
0.0, 1.5,-0.5, 1.0, 0.0, 1.0,-0.5, 1.0, 0.0, 2.0, 0.0, 2.0,
2.0, 2.0, 0.0, 2.0, 1.0, 1.0, 0.5, 1.0, 1.5, 1.5, 0.5, 1.0,
1.5, 1.5, 0.5, 1.0, 2.0, 2.0, 0.5, 1.0, 4.0, 4.0, 0.0, 2.0,
4.0, 4.0, 0.0, 2.0, 2.0, 2.0,-0.5, 1.0, 1.5, 1.5,-0.5, 1.0,
1.5, 1.5,-0.5, 1.0, 1.0, 1.0,-0.5, 1.0, 2.0, 2.0, 0.0, 2.0,
4.0, 0.0, 0.0, 4.0, 2.0, 0.0, 1.0, 2.0, 3.0, 0.0, 1.0, 2.0,
3.0, 0.0, 1.0, 2.0, 4.0, 0.0, 1.0, 2.0, 8.0, 0.0, 0.0, 4.0,
8.0, 0.0, 0.0, 4.0, 4.0, 0.0,-1.0, 2.0, 3.0, 0.0,-1.0, 2.0,
3.0, 0.0,-1.0, 2.0, 2.0, 0.0,-1.0, 2.0, 4.0, 0.0, 0.0, 4.0,
};
/*
* Control points of a torus in NURBS form. Can be rendered using
* the GLU NURBS routines.
*/
static GLfloat torusnurbpts[] = {
4.0, 0.0, 0.0, 4.0, 2.0, 0.0, 1.0, 2.0, 4.0, 0.0, 1.0, 2.0,
8.0, 0.0, 0.0, 4.0, 4.0, 0.0,-1.0, 2.0, 2.0, 0.0,-1.0, 2.0,
4.0, 0.0, 0.0, 4.0, 2.0,-2.0, 0.0, 2.0, 1.0,-1.0, 0.5, 1.0,
2.0,-2.0, 0.5, 1.0, 4.0,-4.0, 0.0, 2.0, 2.0,-2.0,-0.5, 1.0,
1.0,-1.0,-0.5, 1.0, 2.0,-2.0, 0.0, 2.0,-2.0,-2.0, 0.0, 2.0,
-1.0,-1.0, 0.5, 1.0,-2.0,-2.0, 0.5, 1.0,-4.0,-4.0, 0.0, 2.0,
-2.0,-2.0,-0.5, 1.0,-1.0,-1.0,-0.5, 1.0,-2.0,-2.0, 0.0, 2.0,
-4.0, 0.0, 0.0, 4.0,-2.0, 0.0, 1.0, 2.0,-4.0, 0.0, 1.0, 2.0,
-8.0, 0.0, 0.0, 4.0,-4.0, 0.0,-1.0, 2.0,-2.0, 0.0,-1.0, 2.0,
-4.0, 0.0, 0.0, 4.0,-2.0, 2.0, 0.0, 2.0,-1.0, 1.0, 0.5, 1.0,
-2.0, 2.0, 0.5, 1.0,-4.0, 4.0, 0.0, 2.0,-2.0, 2.0,-0.5, 1.0,
-1.0, 1.0,-0.5, 1.0,-2.0, 2.0, 0.0, 2.0, 2.0, 2.0, 0.0, 2.0,
1.0, 1.0, 0.5, 1.0, 2.0, 2.0, 0.5, 1.0, 4.0, 4.0, 0.0, 2.0,
2.0, 2.0,-0.5, 1.0, 1.0, 1.0,-0.5, 1.0, 2.0, 2.0, 0.0, 2.0,
4.0, 0.0, 0.0, 4.0, 2.0, 0.0, 1.0, 2.0, 4.0, 0.0, 1.0, 2.0,
8.0, 0.0, 0.0, 4.0, 4.0, 0.0,-1.0, 2.0, 2.0, 0.0,-1.0, 2.0,
4.0, 0.0, 0.0, 4.0,
};